package me.pearjelly.pmc.service.impl;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import me.pearjelly.pmc.model.PicGroupDoc;
import me.pearjelly.pmc.search.SearcherManager;
import me.pearjelly.pmc.service.SimpleSearchService;
import me.pearjelly.pmc.util.Logger;
import me.pearjelly.pmc.util.Pagination;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.QueryParser.Operator;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.util.Version;

public class SimpleSearchServiceImpl implements SimpleSearchService {

	/**
	 * 默认使用imdic分词器
	 */
	public SimpleSearchServiceImpl() {
		this.analyzer = new SmartChineseAnalyzer(Version.LUCENE_30);
		this.multiFieldQueryParser = new MultiFieldQueryParser(
				Version.LUCENE_30, new String[] { "name", "cateId" }, analyzer);
		this.multiFieldQueryParser.setDefaultOperator(Operator.AND);
		this.nameQueryParser = new QueryParser(Version.LUCENE_30, "name",
				analyzer);
		this.cateIdQueryParser = new QueryParser(Version.LUCENE_30, "cateId",
				analyzer);
		this.maxCount = 1000;
		this.filter = null;
		this.sort = new Sort(new SortField("id", SortField.LONG, true));
		log.info("Use default analyzer:%s", this.analyzer.toString());
	}

	@Override
	public TopDocs searchMuti(String item, String cateId,
			IndexSearcher indexSearcher) {
		String key = new StringBuilder(item).append(" ").append(cateId)
				.toString();
		try {
			Query query = multiFieldQueryParser.parse(key);
			log.debug("MutiQuery:%s", query.toString());
			return indexSearcher.search(query, this.filter, this.maxCount,
					this.sort);
		} catch (ParseException e) {
			log.error("MutiQuery search documents ParseException:%s", e
					.getMessage());
		} catch (IOException e) {
			log.error("MutiQuery search documents IOException:%s", e
					.getMessage());
		}
		return null;
	}

	@Override
	public TopDocs searchName(String item, IndexSearcher indexSearcher) {
		try {
			Query query = nameQueryParser.parse(item);
			log.debug("Query:%s", query.toString());
			return indexSearcher.search(query, this.filter, this.maxCount,
					this.sort);
		} catch (ParseException e) {
			log.error("Query search documents ParseException:%s", e
					.getMessage());
		} catch (IOException e) {
			log.error("Query search documents IOException:%s", e.getMessage());
		}
		return null;
	}

	@Override
	public TopDocs searchCateId(String cateId, IndexSearcher indexSearcher) {
		try {
			Query query = cateIdQueryParser.parse(cateId);
			log.debug("Query:%s", query.toString());
			return indexSearcher.search(query, this.filter, this.maxCount,
					this.sort);
		} catch (ParseException e) {
			log.error("Query search documents ParseException:%s", e
					.getMessage());
		} catch (IOException e) {
			log.error("Query search documents IOException:%s", e.getMessage());
		}
		return null;
	}

	@Override
	public List<PicGroupDoc> pageSearch(String item, String cateId,
			Pagination pagination) {
		List<PicGroupDoc> result = new LinkedList<PicGroupDoc>();
		pagination.setRecordSum(0);

		// 保持indexSearcher一致
		IndexSearcher indexSearcher = SearcherManager.instance();
		TopDocs topDocs = null;
		if (StringUtils.isNotEmpty(item) && StringUtils.isNotEmpty(cateId)) {
			topDocs = searchMuti(item, cateId, indexSearcher);
		} else if (StringUtils.isNotEmpty(item)) {
			topDocs = searchName(item, indexSearcher);
		} else if (StringUtils.isNotEmpty(cateId)) {
			topDocs = searchCateId(cateId, indexSearcher);
		}
		if (topDocs != null) {
			ScoreDoc[] docs = topDocs.scoreDocs;
			pagination.setRecordSum(docs.length < topDocs.totalHits ? docs.length : topDocs.totalHits);
			for (int i = pagination.getStartIndex(); i<docs.length && i <= pagination
					.getEndIndex(); i++) {
				try {
					Document document = indexSearcher.doc(docs[i].doc);
					log.debug("Read document: %s", document);					
					result.add(new PicGroupDoc(document));
				} catch (CorruptIndexException e) {
					log.error("Read document CorruptIndexException:%s", e
							.getMessage());
				} catch (IOException e) {
					log.error("Read document IOException:%s", e.getMessage());
				}
			}
		}

		log.info("item:%s, cate:%s, result size:%d, page:%s.", item, cateId,
				result.size(), pagination.toString());
		return result;
	}

	private static final Logger log = new Logger();

	private Analyzer analyzer;
	private MultiFieldQueryParser multiFieldQueryParser;
	private QueryParser nameQueryParser;
	private QueryParser cateIdQueryParser;
	private int maxCount = Integer.MAX_VALUE;
	private Filter filter;
	private Sort sort;

	public void setAnalyzer(Analyzer analyzer) {
		this.analyzer = analyzer;
		this.multiFieldQueryParser = new MultiFieldQueryParser(
				Version.LUCENE_30, new String[] { "name", "cateId" }, analyzer);
		this.multiFieldQueryParser.setDefaultOperator(Operator.AND);
		this.nameQueryParser = new QueryParser(Version.LUCENE_30, "name",
				analyzer);
		this.cateIdQueryParser = new QueryParser(Version.LUCENE_30, "cateId",
				analyzer);
		log.info("Use injected analyzer:%s", this.analyzer.toString());
	}

	public void setMaxCount(int maxCount) {
		this.maxCount = maxCount > 0 ? maxCount : Integer.MAX_VALUE;
	}

	public void setSort(Sort sort) {
		this.sort = sort;
	}
}
